Coverage Report

Created: 2025-05-07 21:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\dynamic\src\buffer\bytes.rs
Line
Count
Source
1
// Copyright (c) 2025, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use std::alloc::{alloc, dealloc, realloc, Layout};
30
use std::cell::Cell;
31
use std::ptr::copy_nonoverlapping;
32
use std::ops::{Range, RangeFrom, RangeTo};
33
use std::ptr::NonNull;
34
use std::slice;
35
36
pub trait Index {
37
    type Output;
38
    fn index(&self, bytes: &Bytes) -> Self::Output;
39
}
40
41
impl Index for usize {
42
    type Output = u8;
43
44
0
    fn index(&self, bytes: &Bytes) -> Self::Output {
45
0
        let ptr = bytes.bytes.get();
46
0
        let len = bytes.len.get();
47
0
        if *self > len {
  Branch (47:12): [Folded - Ignored]
  Branch (47:12): [True: 0, False: 0]
48
0
            panic!("Cannot index, index out of bounds: {} > {}", *self, len);
49
0
        }
50
0
        unsafe { *ptr.add(*self).as_ptr() }
51
0
    }
52
}
53
54
impl Index for Range<usize> {
55
    type Output = Bytes;
56
57
86
    fn index(&self, bytes: &Bytes) -> Self::Output {
58
86
        let required_len = self.len();
59
86
        let len = bytes.len.get();
60
86
        if required_len > len {
  Branch (60:12): [True: 0, False: 8]
  Branch (60:12): [True: 0, False: 78]
61
0
            panic!("Cannot slice, range out of bounds: {} > {} ({}..{})", required_len, len, self.start, self.end);
62
86
        }
63
86
        let bytes = unsafe { bytes.bytes.get().add(self.start) };
64
86
        Bytes {
65
86
            bytes: Cell::new(bytes),
66
86
            len: Cell::new(self.len()),
67
86
            owned: false,
68
86
        }
69
86
    }
70
}
71
72
impl Index for RangeFrom<usize> {
73
    type Output = Bytes;
74
75
21
    fn index(&self, bytes: &Bytes) -> Self::Output {
76
21
        (self.start..bytes.len.get()).index(bytes)
77
21
    }
78
}
79
80
impl Index for RangeTo<usize> {
81
    type Output = Bytes;
82
83
36
    fn index(&self, bytes: &Bytes) -> Self::Output {
84
36
        (0..self.end).index(bytes)
85
36
    }
86
}
87
88
#[derive(Debug)]
89
pub struct Bytes {
90
    bytes: Cell<NonNull<u8>>,
91
    len: Cell<usize>,
92
    owned: bool,
93
}
94
95
impl Bytes {
96
13
    pub fn from_slice(slice: &[u8]) -> Bytes {
97
13
        let ptr = unsafe { alloc(Layout::array::<u8>(slice.len()).unwrap()) };
98
13
        unsafe { copy_nonoverlapping(slice.as_ptr(), ptr, slice.len()) };
99
13
        Bytes {
100
13
            bytes: unsafe { Cell::new(NonNull::new_unchecked(ptr)) },
101
13
            len: Cell::new(slice.len()),
102
13
            owned: true,
103
13
        }
104
13
    }
105
106
4
    pub fn with_capacity(capacity: usize) -> Bytes {
107
4
        let ptr = unsafe { alloc(Layout::array::<u8>(capacity).unwrap()) };
108
4
        unsafe { ptr.write_bytes(0, capacity); }
109
4
        Bytes {
110
4
            bytes: unsafe { Cell::new(NonNull::new_unchecked(ptr)) },
111
4
            len: Cell::new(capacity),
112
4
            owned: true,
113
4
        }
114
4
    }
115
116
11
    pub unsafe fn copy(&mut self, slice: &[u8]) -> bool {
117
11
        let 
added_bytes6
= match self.resize(slice.len()) {
118
6
            Some(v) => v,
119
            None => {
120
5
                *self = Bytes::from_slice(slice);
121
5
                return true;
122
            }
123
        };
124
6
        copy_nonoverlapping(slice.as_ptr(), self.bytes.get().as_ptr(), slice.len());
125
6
        added_bytes == 0
126
11
    }
127
128
11
    unsafe fn resize(&mut self, new_len: usize) -> Option<usize> {
129
11
        let mut ptr = self.bytes.get();
130
11
        let len = self.len.get();
131
11
        if new_len == len {
  Branch (131:12): [True: 3, False: 0]
  Branch (131:12): [True: 2, False: 6]
132
5
            return Some(0);
133
6
        }
134
6
        if new_len < len {
  Branch (134:12): [True: 0, False: 0]
  Branch (134:12): [True: 1, False: 5]
135
            //FIXME: we need capacity support
136
1
            return Some(0);
137
5
        }
138
5
        if !self.owned {
  Branch (138:12): [True: 0, False: 0]
  Branch (138:12): [True: 5, False: 0]
139
5
            return None;
140
0
        }
141
0
        ptr = unsafe { NonNull::new_unchecked(realloc(ptr.as_ptr(), Layout::array::<u8>(len).unwrap(), new_len)) };
142
        // The number of bytes which were added in the realloc.
143
0
        let ending = new_len - len;
144
        //unsafe { write_bytes(ptr.add(len).as_ptr(), 0, ending) }
145
0
        self.bytes.set(ptr);
146
0
        self.len.set(new_len);
147
0
        Some(ending)
148
11
    }
149
150
201
    pub fn as_bytes(&self) -> &[u8] {
151
201
        let ptr = self.bytes.get();
152
201
        let len = self.len.get();
153
201
        unsafe { slice::from_raw_parts(ptr.as_ptr(), len) }
154
201
    }
155
156
19
    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
157
19
        let ptr = self.bytes.get();
158
19
        let len = self.len.get();
159
19
        unsafe { slice::from_raw_parts_mut(ptr.as_ptr(), len) }
160
19
    }
161
162
86
    pub fn index<I: Index>(&self, index: I) -> I::Output {
163
86
        index.index(self)
164
86
    }
165
166
144
    pub fn len(&self) -> usize {
167
144
        self.len.get()
168
144
    }
169
170
40
    pub unsafe fn delete(&mut self) {
171
40
        if self.owned {
  Branch (171:12): [True: 1, False: 4]
  Branch (171:12): [True: 9, False: 26]
172
10
            unsafe { dealloc(self.bytes.get().as_ptr(), Layout::array::<u8>(self.len.get()).unwrap()) }
173
30
        }
174
40
    }
175
}